package Commons;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**La classe contiene delle funzionalità comuni utilizzate da più package.
 *
 * @author Team5
 */
public class Utility {

    private DatagramSocket ds;
    private DatagramPacket dp;

    private InetAddress mittente;
    private int portaMittente;

    /**
     * L'attributo sarà true se il Server di Ricezione UDP è stato inizializzato, chiamando sull'ogetto Utility il metodo inizializzaServerRicezioneUDP(porta)
     */
    boolean ServerRicezioneUDPinizializzato;

    public Utility(){
        ServerRicezioneUDPinizializzato=false;
    }

    /**Il metodo permette di inviare un qualsiasi oggetto mediante serializzazione, tramite protocollo UDP.
     *
     * @param obj Oggetto generico che implementa serializable
     * @param address indirizzo IP a cui inviare l'oggetto
     * @param porta porta alla quale inviare l'ogetto
     * @throws SocketException
     * @throws IOException
     */
    public void invioOggettoSerializzatoUDP(Object obj,InetAddress address,int porta) throws SocketException, IOException{

            ObjectOutputStream oos; 
            ds=new DatagramSocket();            
            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            byte [ ] data=new byte[2048] ;//1024 non bastava
            dp= new DatagramPacket(data,data.length, address, porta);
            ObjectOutputStream ous = new ObjectOutputStream(baos);
            ous.writeObject(obj);
            ous.flush ( );
            data=baos.toByteArray();
            dp.setData(data);
            dp.setLength(data.length);
            System.out.println("invioOggettoSerializzato(): Sto inviando...");
            ds.send(dp);
            System.out.println("invioOggettoSerializzato(): Ho inviato...");
            baos.reset();

    }


/**Questo metodo serve ad inizializzare la Socket di ricezione UDP nel server.
 * In ingresso richiede solo la porta su cui inizializzare la connessione.
 * Gli ogetti delle classi DatagramSocket e DatagramPacket creati da questo metodo, vengono memorizzate nell'ogetto Utility su cui il metodo viene chiamato.
 * Dopo aver eseguito questo metodo di inizializzazione, è possibile chiamare sullo stesso ogetto Utility il metodo riceviOggettoSerializzatoUDP().
 *
 * @param port porta su cui avviare la socket UDP in ricezione
 * @throws SocketException
 */

    public void inizializzaServerRicezioneUDP(int port) {
        System.out.println("START inizializzaServerRicezioneUDP()");
        try {
            ds = new DatagramSocket(port);
        } catch (SocketException ex) {
            System.out.println("Eccezione in inizializzaRicezioneUDP sulla porta "+port);
            
            Logger.getLogger(Utility.class.getName()).log(Level.SEVERE, null, ex);
            
        }
            byte buffer[ ]=new byte[2048];//anke qui
            dp=new DatagramPacket(buffer,buffer.length);
            this.ServerRicezioneUDPinizializzato=true;
            
    }

    /**Questo metodo permette di ricevere un qualsiasi oggetto serializzato, mediante socket UDP.
     *ATTENZIONE: per poter avviare questo metodo su un ogetto Utility, è necessario aver precedentemente richiamato sullo stesso ogetto il metodo inizializzaServerRicezioneUDP(porta); in caso contrario verrò sollevata un eccezione.
     *
     * @return Oggetto serializzato ricevuto
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws Exception
     */
    public Object riceviOggettoSerializzatoUDP() throws IOException, ClassNotFoundException, Exception{
        if(this.ServerRicezioneUDPinizializzato){
                System.out.println("In attesa...");
                ds.receive(dp);
                //PARTE AGGIUNTA DA I PEPI
                    this.mittente=dp.getAddress();
                    this.portaMittente=dp.getPort();
                    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&"+dp.getLength());
                //FINE PARTE AGGIUNTA DA I PEPI
                ByteArrayInputStream bais= new ByteArrayInputStream(dp.getData());
                ObjectInputStream ois= new ObjectInputStream (bais);

                return ois.readObject();
        }else
            throw new Exception("Server di ricezione non inizializzato. Esegui prima il metodo inizializzaServerRicezioneUDP");
    }
    public boolean getStatoInizializzazioneServerRicezioneUDP(){
        return this.ServerRicezioneUDPinizializzato;
    }

    public InetAddress getMittente() {
        return mittente;
    }

    public int getPortaMittente() {
        return portaMittente;
    }
    
    public void chiudiSocket(){
        try
        {
           this.ds.close();
            
        }
        catch(Exception e)
        {
             System.out.println("Eccezione: Sulla chiusura del Socket.");
        }

    }

}
